<?php

namespace Biz\Services\Site;

use Biz\Criteria\Site\Paper\FullOrPassedFilterCriterion;
use Biz\Models\Site\SitePaperTheme;
use Lumen\Logger\Logger;
use Biz\Models\User\User;
use Illuminate\Http\Request;
use Biz\Models\Site\SitePaper;
use Biz\Libraries\TranslationUtil;
use Illuminate\Support\Facades\DB;
use Biz\Constants\Site\SitePaperConstants;
use Biz\Criteria\Site\SiteFilterCriterion;
use Biz\Criteria\Site\UserFilterCriterion;
use Biz\Criteria\Site\LocaleFilterCriterion;
use Biz\Criteria\Site\NumberFilterCriterion;
use Lumen\Core\Exceptions\BusinessException;
use Biz\Repositories\Site\SitePaperRepository;
use Illuminate\Contracts\Pagination\Paginator;
use Biz\Criteria\Site\Paper\FullFilterCriterion;
use Biz\Constants\Site\SitePaperAbstractConstants;
use Biz\Criteria\Site\Paper\AbstractOrFullFilterCriterion;

/**
 * SitePaperService.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class SitePaperService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $paperThemeService;

    /**
     * RepositoryController constructor.
     *
     * @param SitePaperRepository $repository
     * @param SitePaperThemeService $paperThemeService
     */
    public function __construct(SitePaperRepository $repository, SitePaperThemeService $paperThemeService)
    {
        $this->repository              = $repository;
        $this->paperThemeService              = $paperThemeService;
    }

    /**
     * 客户中台列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function search(Request $request): Paginator
    {
        $site_id  = $request->get('site_id');
        $pageSize = $request->get('page_size', 10);

        $results = $this->repository
            ->with(['authors', 'abstract', 'full', 'theme', 'translations'])
            ->setCacheLifetime(0)
            ->pushCriterion(new SiteFilterCriterion($site_id))
            //->pushCriterion(new LocaleFilterCriterion())
            ->paginate($pageSize);

        return $results;
    }

    /**
     * 前台会员摘要列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function getUserPaperAbstractList(Request $request): Paginator
    {
        /** @var User $user */
        $user    = $request->user();
        $site_id = $request->get('site_id');

        $results = $this->repository
            ->with(['abstract', 'translations'])
            ->setCacheLifetime(0)
            ->pushCriterion(new SiteFilterCriterion($site_id))
            ->pushCriterion(new UserFilterCriterion($user->id))
            ->pushCriterion(new AbstractOrFullFilterCriterion())
            ->paginate(10);

        return $results;
    }

    /**
     * 前台会员全文列表页.
     *
     * @param Request $request
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function getUserPaperFullList(Request $request): Paginator
    {
        /** @var User $user */
        $user    = $request->user();
        $site_id = $request->get('site_id');

        $results = $this->repository
            ->with(['abstract', 'full', 'translations'])
            ->setCacheLifetime(0)
            ->pushCriterion(new SiteFilterCriterion($site_id))
            ->pushCriterion(new UserFilterCriterion($user->id))
            ->pushCriterion(new FullOrPassedFilterCriterion())
            ->paginate(10);

        return $results;
    }

    /**
     * Find.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function find(int $id): SitePaper
    {
        $paper = $this->repository->find($id);
        if (is_null($paper)) {
            throw new BusinessException(trans('site.paper_not_found'));
        }

        return $paper;
    }

    /**
     * Find By Number.
     *
     * @param string $number
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function findByNumber(string $number): SitePaper
    {
        $paper = $this->repository->setCacheLifetime(0)->pushCriterion(new NumberFilterCriterion($number))->findFirst();
        if (is_null($paper)) {
            throw new BusinessException(trans('site.paper_not_found'));
        }

        return $paper;
    }

    /**
     * Find By uid.
     *
     * @param string $uid
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function findByUid(string $uid): SitePaper
    {
        $id   = SitePaper::decodeUid($uid);

        return $this->find($id);
    }

    /**
     * With find.
     *
     * @param int   $id
     * @param array $with
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function findWith(int $id, $with = []): SitePaper
    {
        $site = $this->repository->with($with)->find($id);
        if (is_null($site)) {
            throw new BusinessException(trans('site.paper_not_found'));
        }

        return $site;
    }

    /**
     * Find By Site Id.
     *
     * @param int $site_id
     *
     * @throws BusinessException
     *
     * @return bool
     */
    public function findBySiteId(int $site_id)
    {
        $paper = $this->repository
            ->pushCriterion(new SiteFilterCriterion($site_id))
            ->findFirst();

        return $paper;
    }

    /**
     * Check By Number.
     *
     * @param string $number
     *
     * @throws BusinessException
     *
     * @return void
     */
    public function checkByNumber(string $number): void
    {
        $paper = $this->repository->setCacheLifetime(0)->pushCriterion(new NumberFilterCriterion($number))->findFirst();
        if ($paper) {
            throw new BusinessException(trans('site.paper_number_has_already_existed'));
        }
    }

    /**
     * Is Abstract Status.
     *
     * @param SitePaper $paper
     *
     * @throws BusinessException
     *
     * @return void
     */
    public function mustStatusAbstract(SitePaper $paper): void
    {
        if (SitePaperConstants::STATUS_ABSTRACT !== $paper->status) {
            throw new BusinessException(trans('site/paper/paper.must_status_abstract'));
        }
    }

    /**
     * Is Full Status.
     *
     * @param SitePaper $paper
     *
     * @throws BusinessException
     *
     * @return void
     */
    public function mustStatusFull(SitePaper $paper): void
    {
        if (SitePaperConstants::STATUS_FULL !== $paper->status) {
            throw new BusinessException(trans('site/paper/paper.must_status_full'));
        }
    }

    /**
     * Update Status to Full.
     *
     * @param SitePaper $paper
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function updateStatusFull(SitePaper $paper): SitePaper
    {
        $this->mustStatusAbstract($paper);

        // Update Status
        $data['status'] = SitePaperConstants::STATUS_FULL;

        return $this->repository->update($paper, $data);
    }

    /**
     * Update Status to Passed.
     *
     * @param SitePaper $paper
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function updateStatusPassed(SitePaper $paper): SitePaper
    {
        $this->mustStatusFull($paper);

        // Update Status
        $data['status'] = SitePaperConstants::STATUS_PASSED;

        return $this->repository->update($paper, $data);
    }

    /**
     * Handle Parent Id.
     *
     * @param array $data
     *
     * @return array
     */
    public function handleThemeId(array $data): array
    {
        if(!isset($data['theme_id'])){
            $data['theme_id'] = SitePaperConstants::THEME_DEFAULT;
            return $data;
        }

        $theme_id = $data['theme_id'];
        if (SitePaperConstants::THEME_NONE === $theme_id) {
            $data['theme_id'] = SitePaperConstants::THEME_DEFAULT;
        } else {
            /** @var SitePaperTheme $parent */
            $parent            = $this->paperThemeService->findByUid($theme_id);
            $data['theme_id'] = $parent->id;
        }

        return $data;
    }

    /**
     * Store.
     *
     * @param Request $request
     *
     * @throws \Exception
     *
     * @return SitePaper
     */
    public function store(Request $request): SitePaper
    {
        // Get Current User
        /** @var User $user */
        $user = $request->user();

        $data            = $request->all();
        $data['user_id'] = $user->id;

        return $this->create($data);
    }

    /**
     * Create.
     *
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SitePaper
     */
    public function create(array $data): SitePaper
    {
        // Check Number
        $this->checkByNumber($data['number']);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 创建论文
            $data['status'] = SitePaperConstants::STATUS_ABSTRACT;

            $data = TranslationUtil::convertTranslationsData($data);

            $paper   = $this->repository->create($data);
            if (! $paper) {
                throw new BusinessException(trans('site.paper_create_fail'));
            }
            // Load Translations
            $paper->load('translations');

            // 处理作者
            $authors = $data['authors'];
            $paper->authors()->createMany($authors);
            $paper->load('authors');

            // 处理摘要
            $abstract           = $data['abstract'];
            $abstract['status'] = SitePaperAbstractConstants::STATUS_SUBMISSION;
            $paper->abstract()->create($abstract);
            $paper->load('abstract');

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $paper;
    }

    /**
     * Detail.
     *
     * @param string $id
     *
     * @throws BusinessException
     *
     * @return SitePaper
     */
    public function show(string $id): SitePaper
    {
        $id   = SitePaper::decodeUid($id);
        $site = $this->findWith($id, ['authors', 'abstract', 'full', 'theme', 'translations']);

        return $site;
    }

    /**
     * Edit.
     *
     * @param string $id
     * @param array  $data
     *
     * @throws \Exception
     *
     * @return SitePaper
     */
    public function edit(string $id, array $data): SitePaper
    {
        $id   = SitePaper::decodeUid($id);

        return $this->update($id, $data);
    }

    /**
     * Update.
     *
     * @param int   $id
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SitePaper
     */
    public function update(int $id, array $data): SitePaper
    {
        $paper = $this->find($id);

        // 不允许修改编号
        //unset($data['number']);

        // Check Number
        if ($paper->number != $data['number']) {
            $this->checkByNumber($data['number']);
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $data = TranslationUtil::convertTranslationsData($data);

            $paper   = $this->repository->update($paper, $data);
            if (! $paper) {
                throw new BusinessException(trans('site.paper_create_fail'));
            }

            // 处理作者
            $authors = $data['authors'];
            $paper->authors()->delete();
            $paper->authors()->createMany($authors);
            $paper->load('authors');

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $paper;
    }

    /**
     * Remove.
     *
     * @param string $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function remove(string $id): bool
    {
        $id   = SitePaper::decodeUid($id);

        return $this->delete($id);
    }

    /**
     * Delete.
     *
     * @param int $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(int $id): bool
    {
        /** @var SitePaper $paper */
        $paper = $this->find($id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $this->repository->delete($paper);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return true;
    }

    /**
     * Delete Translations.
     *
     * @param string $id
     * @param string $locale
     *
     * @return bool
     */
    public function deleteTranslations(string $id, string $locale): bool
    {
        /** @var SitePaper $paper */
        $paper = $this->findByUid($id);

        $paper->deleteTranslations($locale);

        return true;
    }

    /**
     * 设置指定论文的主题ID为默认值
     *
     * @param int $theme_id
     *
     * @return bool
     */
    public function themeDefault(int $theme_id): bool
    {
        /** @var SitePaper $paper */
        SitePaper::where('theme_id', $theme_id)->update([
            'theme_id' => 0
        ]);

        return true;
    }

}
